package com.indi.gulimall.product.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.indi.common.to.SkuStockTO;
import com.indi.common.utils.PageUtils;
import com.indi.common.utils.Query;
import com.indi.common.utils.R;
import com.indi.gulimall.product.dao.SkuInfoDao;
import com.indi.gulimall.product.entity.SkuImagesEntity;
import com.indi.gulimall.product.entity.SkuInfoEntity;
import com.indi.gulimall.product.entity.SpuInfoDescEntity;
import com.indi.gulimall.product.feign.SeckillFeignService;
import com.indi.gulimall.product.feign.WareFeignService;
import com.indi.gulimall.product.service.*;
import com.indi.gulimall.product.vo.SeckillSkuRedisVO;
import com.indi.gulimall.product.vo.SkuSearchVO;
import com.indi.gulimall.product.vo.web.SkuItemVO;
import com.indi.gulimall.product.vo.web.SkuItemVO.SaleAttrVO;
import com.indi.gulimall.product.vo.web.SkuItemVO.SpuAttrGroupVO;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;


@Service("skuInfoService")
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoDao, SkuInfoEntity> implements SkuInfoService {
    @Resource
    private SpuInfoDescService spuInfoDescService;

    @Resource
    private SkuImagesService skuImagesService;

    @Resource
    private ProductAttrValueService attrValueService;

    @Resource
    private SkuSaleAttrValueService saleAttrValueService;

    @Resource
    private ThreadPoolExecutor executor;

    @Resource
    private WareFeignService wareFeignService;

    @Resource
    private SeckillFeignService seckillFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params),
                new QueryWrapper<SkuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params, SkuSearchVO skuSearchVO) {
        QueryWrapper<SkuInfoEntity> queryWrapper = new QueryWrapper<>();

        if (StringUtils.isNotEmpty(skuSearchVO.getKey())) {
            queryWrapper.and(wrapper -> wrapper.eq("sku_id", skuSearchVO.getKey()).or().like("sku_name", skuSearchVO.getKey()));
        }

        if (skuSearchVO.getBrandId() != null && skuSearchVO.getBrandId().intValue() != 0) {
            queryWrapper.eq("brand_id", skuSearchVO.getBrandId());
        }

        if (skuSearchVO.getCategoryId() != null && skuSearchVO.getCategoryId().intValue() != 0) {
            queryWrapper.eq("category_id", skuSearchVO.getCategoryId());
        }

        if (skuSearchVO.getMinPrice() != null && skuSearchVO.getMinPrice().intValue() >= 0) {
            queryWrapper.ge("price", skuSearchVO.getMinPrice());
        }

        if (skuSearchVO.getMaxPrice() != null && skuSearchVO.getMaxPrice().compareTo(BigDecimal.ZERO) == 1) {
            queryWrapper.le("price", skuSearchVO.getMaxPrice());
        }

        IPage<SkuInfoEntity> page = this.page(
                new Query<SkuInfoEntity>().getPage(params),
                queryWrapper
        );
        return new PageUtils(page);
    }

    @Override
    public List<SkuInfoEntity> listBySpuId(Long spuId) {
        List<SkuInfoEntity> skuInfoList = this.list(new QueryWrapper<SkuInfoEntity>().eq("spu_id", spuId));
        return skuInfoList;
    }

    @Override
    public SkuItemVO getSkuItemVO(Long skuId) throws ExecutionException, InterruptedException {
        SkuItemVO skuItemVO = new SkuItemVO();

        CompletableFuture<SkuInfoEntity> infoFuture = CompletableFuture.supplyAsync(() -> {
            // sku基本信息获取 skuInfo
            SkuInfoEntity skuInfo = this.getById(skuId);
            skuItemVO.setSkuInfo(skuInfo);
            return skuInfo;
        }, executor);

        CompletableFuture<Void> descFuture = infoFuture.thenAcceptAsync(res -> {
            // spu 的介绍
            SpuInfoDescEntity spuInfoDesc = spuInfoDescService.getById(res.getSpuId());
            skuItemVO.setSpuInfoDesc(spuInfoDesc);
        }, executor);


        CompletableFuture<Void> baseAttrFuture = infoFuture.thenAcceptAsync(res -> {
            // 获取spu 的规格参数及其所属分组
            List<SpuAttrGroupVO> spuAttrGroupVOs = attrValueService.getAttrWithGroupVO(res.getCategoryId(), res.getSpuId());
            skuItemVO.setAttrGroupVOs(spuAttrGroupVOs);
        }, executor);

        CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync(res -> {
            // spu 销售属性组合
            List<SaleAttrVO> saleAttrVOs = saleAttrValueService.getSaleAttrValues(res.getSpuId());
            skuItemVO.setSaleAttrVOs(saleAttrVOs);
        }, executor);

        CompletableFuture<Void> imagesFuture = CompletableFuture.runAsync(() -> {
            // sku 图片信息	skuImages
            List<SkuImagesEntity> skuImages = skuImagesService.listBySkuId(skuId);
            skuItemVO.setSkuImages(skuImages);
        }, executor);

        CompletableFuture<Void> stockFuture = CompletableFuture.runAsync(() -> {
            // 当前 sku 是否有货
            R r = wareFeignService.stockOrNot(Arrays.asList(skuId));
            if (r.getCode() == 0) {
                List<SkuStockTO> data = r.getData(new TypeReference<List<SkuStockTO>>() {
                });
                if (data != null && data.size() > 0) {
                    skuItemVO.setStockOrNot(data.get(0).getStockOrNot());
                } else {
                    skuItemVO.setStockOrNot(false);
                }
            }
        }, executor);

        CompletableFuture<Void> seckillFuture = CompletableFuture.runAsync(() -> {
            // 当前 sku 的秒杀信息
            R r = seckillFeignService.getSeckillSkuRelation(skuId);
            if (r.getCode() == 0) {
                SeckillSkuRedisVO seckillSkuRedisVO = r.getData(new TypeReference<SeckillSkuRedisVO>() {
                });
                skuItemVO.setSeckillInfo(seckillSkuRedisVO);
            }
        }, executor);

        CompletableFuture.allOf(descFuture, baseAttrFuture, saleAttrFuture, imagesFuture, stockFuture, seckillFuture).get();
        return skuItemVO;
    }

}